package verappdesktop.views;

import java.util.Iterator;
import java.util.Map.Entry;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

import verappdesktop.core.Variable;
import verappdesktop.core.VerappDesktop;
import verappdesktop.utils.VariableDataSet;

public class GraphView extends JPanel{
	private double minX, minY, maxX, maxY;
	private DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
	private JFreeChart chart;
	private ChartPanel chartPanel = new ChartPanel(null);

	public GraphView(){
		this(0,0,10,10);
	}
	
	public GraphView(double minX, double minY, double maxX, double maxY){
		this.minX = minX;
		this.minY = minY;
		this.maxX = maxX;
		this.maxY = maxY;
		add(chartPanel);
	}
	
	//XXX - Argument should probably be enums or whatever to prevent nonexistent variables from being drawn.
	//This is probably handled well enough now.
	/**
	 * Adds the specified variable to the collection of variables drawn in the graph.
	 * @param varName
	 * @return True if the variable is already drawn. False otherwise.
	 */
	/*public boolean addVariable(Variable var){
		if (VerappDesktop.getAvailableVariables().contains(var)){
			boolean added = drawnVariables.add(var);
			if (added){
				reDraw();
			}
			return added;
		}
		throw new IllegalArgumentException("Invalid variable. Must be one of the variables loaded at startup.");
	}*/
	public boolean addVariable(VariableDataSet var){
		if (VerappDesktop.getAvailableVariables().contains(var.getVariable())){
			if (dataSet.getRowIndex(var.getVariable().getName()) == -1){
				Iterator<Entry<Double,Double>> it = var.getData().entrySet().iterator();
				Entry<Double,Double> pair;
				while (it.hasNext()){
					pair = it.next();
					dataSet.setValue(pair.getValue(), var.getVariable().getName(), pair.getKey());
				}
				reDraw();
				return true;
			}
			else {
				return false;
			}
		}
		throw new IllegalArgumentException("Invalid variable. Must be one of the variables loaded at startup.");
	}
	
	/**
	 * Removes the specified variable from the collection of variables drawn in the graph.
	 * @return True if the variable was drawn. False otherwise.
	 */
	/*public boolean removeVariable(Variable var){
		if (VerappDesktop.getAvailableVariables().contains(var)){
			boolean removed = drawnVariables.remove(var);
			if (removed){
				reDraw();
			}
			return removed;
		}
		throw new IllegalArgumentException("Invalid variable. Must be one of the variables loaded at startup.");
	}*/
	
	public boolean removeVariable(Variable var){
		if (VerappDesktop.getAvailableVariables().contains(var)){
			if (dataSet.getRowIndex(var.getName()) != -1){
				dataSet.removeRow(var.getName());
				reDraw();
				return true;
			}
			else {
				return false;
			}
		}
		throw new IllegalArgumentException("Invalid variable. Must be one of the variables loaded at startup.");
	}
	
	private void reDraw(){
		chart = ChartFactory.createLineChart("", "Time", "", dataSet, PlotOrientation.VERTICAL, true, 
				false, false);
		chartPanel.setChart(chart);
		revalidate();
	}
	
	//XXX - Getters for x/y are probaly not needed.
	public double getMinX() {
		return minX;
	}

	public void setMinX(double minX) {
		if (minX < maxX){
			this.minX = minX;
		}
		else {
			throw new IllegalArgumentException("minX has to be smaller than maxX. Current maxX: " + 
											   	maxX + "Provided minX: " + minX);
		}
	}

	public double getMinY() {
		return minY;
	}

	public void setMinY(double minY) {
		if (minY < maxY){
			this.minY = minY;
		}
		else {
			throw new IllegalArgumentException("minY has to be smaller than maxY. Current maxY: " + 
											   	maxY + "Provided minY: " + minY);
		}
	}

	public double getMaxX() {
		return maxX;
	}

	public void setMaxX(double maxX) {
		if (maxX > minX){
			this.maxX = maxX;
		}
		else {
			throw new IllegalArgumentException("maxX has to be larger than minX. Current minX: " + 
											   	minX + "Provided maxX: " + maxX);
		}
	}

	public double getMaxY() {
		return maxY;
	}

	public void setMaxY(double maxY) {
		if (maxY > minY){
			this.maxY = maxY;
		}
		else {
			throw new IllegalArgumentException("maxY has to be larger than minY. Current minY: " + 
											   	minY + "Provided maxY: " + maxY);
		}
	}
}
